package com.ruoyi.web.controller.system;

import com.github.pagehelper.PageInfo;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.page.PageDomain;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.page.TableSupport;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.system.domain.vo.SimpleUserResVO;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.tools.IMTokenServer;
import com.ruoyi.tools.UserSigTool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.Metric;
import org.springframework.data.geo.Metrics;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.file.MimeTypeUtils;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.service.ISysUserService;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 个人信息 业务处理
 * 
 * @author ruoyi
 */
@RestController
@RequestMapping("/system/user/profile")
public class SysProfileController extends BaseController
{
    @Autowired
    private ISysUserService userService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ISysDeptService deptService;

    /**
     * 个人信息
     */
    @GetMapping
    public AjaxResult profile() throws Exception {
        LoginUser loginUser = getLoginUser();
        SysUser user = loginUser.getUser();
        AjaxResult ajax = AjaxResult.success(user);
        ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername()));
        ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername()));
        ajax.put("userSig", UserSigTool.getUserSig(String.valueOf(user.getUserId()), tokenService.getExpireTime()));
        ajax.put("sdkAppId", RuoYiConfig.getSdkAppId());
        ajax.put("imAppId", RuoYiConfig.getAppKey());
        ajax.put("imToken", IMTokenServer.getUserToken( user.getUserId(), tokenService.getExpireTime()));
        return ajax;
    }

    @GetMapping("/video/list")
    public AjaxResult getVideoList(){
        SysDept sysDept = getLoginUser().getUser().getDept();
        return AjaxResult.success(deptService.getVideoList(sysDept));
    }

    /**
     * 修改用户
     */
    @Log(title = "个人信息", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult updateProfile(@RequestBody SysUser user)
    {
        LoginUser loginUser = getLoginUser();
        SysUser currentUser = loginUser.getUser();
        currentUser.setNickName(user.getNickName());
        currentUser.setEmail(user.getEmail());
        currentUser.setPhonenumber(user.getPhonenumber());
        currentUser.setSex(user.getSex());
        if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser))
        {
            return error("修改用户'" + loginUser.getUsername() + "'失败，手机号码已存在");
        }
        if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser))
        {
            return error("修改用户'" + loginUser.getUsername() + "'失败，邮箱账号已存在");
        }
        if (userService.updateUserProfile(currentUser) > 0)
        {
            // 更新缓存用户信息
            tokenService.setLoginUser(loginUser);
            return success();
        }
        return error("修改个人信息异常，请联系管理员");
    }

    /**
     * 重置密码
     */
    @Log(title = "个人信息", businessType = BusinessType.UPDATE)
    @PutMapping("/updatePwd")
    public AjaxResult updatePwd(String oldPassword, String newPassword)
    {
        LoginUser loginUser = getLoginUser();
        String userName = loginUser.getUsername();
        String password = loginUser.getPassword();
        if (!SecurityUtils.matchesPassword(oldPassword, password))
        {
            return error("修改密码失败，旧密码错误");
        }
        if (SecurityUtils.matchesPassword(newPassword, password))
        {
            return error("新密码不能与旧密码相同");
        }
        newPassword = SecurityUtils.encryptPassword(newPassword);
        if (userService.resetUserPwd(userName, newPassword) > 0)
        {
            // 更新缓存用户密码
            loginUser.getUser().setPassword(newPassword);
            tokenService.setLoginUser(loginUser);
            return success();
        }
        return error("修改密码异常，请联系管理员");
    }

    /**
     * 头像上传
     */
    @Log(title = "用户头像", businessType = BusinessType.UPDATE)
    @PostMapping("/avatar")
    public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception
    {
        if (!file.isEmpty())
        {
            LoginUser loginUser = getLoginUser();
            String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION);
            if (userService.updateUserAvatar(loginUser.getUsername(), avatar))
            {
                AjaxResult ajax = AjaxResult.success();
                ajax.put("imgUrl", avatar);
                // 更新缓存用户头像
                loginUser.getUser().setAvatar(avatar);
                tokenService.setLoginUser(loginUser);
                return ajax;
            }
        }
        return error("上传图片异常，请联系管理员");
    }

    /**
     * 上报用户坐标
     */
    @PostMapping("/update/location/{longitude}/{latitude}")
    public AjaxResult updateLocation(@PathVariable double longitude, @PathVariable double latitude)
    {
        String userId = String.valueOf(getUserId());
        if (userId != null && getDeptId()!= null) {
            redisCache.addGeo(CacheConstants.LOGIN_DEPT_GEO_KEY + getDeptId(), userId, longitude, latitude);
            redisCache.addGeo(CacheConstants.LOGIN_DEPT_GEO_KEY + "all", userId, longitude, latitude);

            return toAjax(true);
        } else {
            return toAjax(false);
        }

    }

    /**
     * 上报用户坐标
     */
    @PostMapping("/test/{userId}/{longitude}/{latitude}")
    public AjaxResult updateLocation(@PathVariable String userId,
                                     @PathVariable double longitude,
                                     @PathVariable double latitude)
    {
        SysUser user = userService.selectUserById(Long.valueOf(userId));
        redisCache.addGeo(CacheConstants.LOGIN_DEPT_GEO_KEY + user.getDeptId(), userId, longitude, latitude);
        redisCache.addGeo(CacheConstants.LOGIN_DEPT_GEO_KEY + "all", userId, longitude, latitude);

        return toAjax(true);
    }

    //查找所有人位置
    @GetMapping("/nearby/all")
    public AjaxResult nearbyAll(@RequestParam(name = "deptId", required = false)  Long deptId)
    {
        String key = "";

        if (deptId == null || deptId == 100L) {
            key = CacheConstants.LOGIN_DEPT_GEO_KEY + "all";
            deptId = null;
        } else {
            key = CacheConstants.LOGIN_DEPT_GEO_KEY + deptId;
        }

        SysUser user = new SysUser();
        user.setDeptId(deptId);
        String finalKey = key;
        List<SimpleUserResVO> list = userService.selectSimpleUserList(user).stream().peek(currentUser ->{
            List <Point> points = redisCache.geoPosition(finalKey, new String[] {Long.toString(currentUser.getUserId())});
            if (!points.isEmpty()){
                currentUser.setPoint(points.get(0));
            }
        }).collect(Collectors.toList());
        return AjaxResult.success(list);
    }

    /**
     * 查找附近用户
     */
    @GetMapping("/nearby")
    public TableDataInfo nearby(@RequestParam("longitude") double longitude,
                                @RequestParam("latitude") double latitude)
    {
        PageDomain pageDomain = TableSupport.buildPageRequest();
        Integer pageNum = pageDomain.getPageNum();
        Integer pageSize = pageDomain.getPageSize();

        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        Long count = redisCache.geoCount(CacheConstants.LOGIN_DEPT_GEO_KEY + getDeptId());

        if (getDeptId() == null) {
            count = redisCache.geoCount(CacheConstants.LOGIN_DEPT_GEO_KEY + "all");
        }
        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> geoResults = redisCache.geoNear(CacheConstants.LOGIN_DEPT_GEO_KEY + getDeptId(), longitude, latitude, 10000, Metrics.MILES, pageSize * pageNum);

        if (geoResults.isEmpty()|| count == 0){
            rspData.setRows(new ArrayList<>());
            rspData.setTotal(0);
            return rspData;
        }

        Map<String, Point> mapList = geoResults.stream()
                .skip((long) (pageNum - 1) * pageSize)
                .map(GeoResult::getContent)
                .collect(Collectors.toMap(RedisGeoCommands.GeoLocation::getName,RedisGeoCommands.GeoLocation::getPoint));
        SysUser user = new SysUser();
        user.setDeptId(getDeptId());
        //获取mapList所有键 转化成Long[]
        Long[] userIds = mapList.keySet().stream().map(String::valueOf).map(Long::parseLong).toArray(Long[]::new);
        user.setUserIds(userIds);
        List<SysUser> userList = userService.selectAllUserList(user);
        List<SysUser> result = userList.stream().map( userInfo -> {
            userInfo.setPoint( mapList.get(String.valueOf(userInfo.getUserId())));
            return userInfo;
        }).collect(Collectors.toList());
        rspData.setRows(result);
        rspData.setTotal(count);
        return rspData;
    }


}
